/*! \file SimpleTriangleApp.cpp
 *	\brief
 *
 *	created:	2009/11/11
 *	created:	11:11:2009   17:15
 *	filename: 	c:\src\main\prjs\SimpleTriangle\SimpleTriangle\SimpleTriangleApp.cpp
 *	file path:	c:\src\main\prjs\SimpleTriangle\SimpleTriangle
 *	file base:	SimpleTriangleApp
 *	file ext:	cpp
 *	author:		Vitalii Trubchaninov
 *				venngraydog@gmail.com
 */
#include "SimpleTriangle/stdafx.h"
#include "SimpleTriangle/SimpleTriangleApp.h"

#include "app/DefaultBindings.h"
#include "app/Window.h"
#include <core/exception.h>
#include <gd/Device.h>
#include <gd/DeviceContext.h>
#include <gd/Driver.h>
#include <gd/Material.h>
#include <gd/MaterialBuilder.h>
#include <gd/Primitive.h>
#include <gd/PrimitiveBuilder.h>
#include <gd/VertexAccessor.h>
#include <gd/VertexFormat.h>
#include <io/StdFileSystem.h>
#include <resource_manager/ResourceManager.h>
#include <resource_manager/SimpleResourceManager.h>
#include <utils/Paths.h>
#include "utils/ProcessUtils.h"

#include "Resource.h"

namespace tt{

const char* CONFIG_FILE_NAME = "config.xml";

SimpleTriangleApp::SimpleTriangleApp()
: Base()
, m_config()
, m_fullScreen(false)
, m_screenWidth(1280)
, m_screenHeight(720)
, m_gd_driver()
, m_gd_device()
, m_gd_context()
, m_material()
, m_primitive()
{
	configRead();
}

SimpleTriangleApp::~SimpleTriangleApp(void)
{
	configWrite();
}

//////////////////////////////////////////////////////////////////////////
void SimpleTriangleApp::update()
{

}

void SimpleTriangleApp::render()
{
	m_gd_context->clear();

	m_material->apply( m_gd_context.get() );
	m_primitive->apply( m_gd_context.get() );

 	m_gd_device->present();
}

//////////////////////////////////////////////////////////////////////////
void SimpleTriangleApp::onCreate()
{
	app::AppFactory::CreateInstance();
	gd::Factory::CreateInstance();

	io::PathW resourcesPath = utils::resourcesPath();
	SharedPtr<io::BaseFileSystem> fs(new io::StdFileSystem(resourcesPath) );
	rm::ResourceManager::CreateInstance( new rm::SimpleResourceManager(fs) );

	SharedPtr<app::Window> window = ttAppFactory().createWindow();
	window->create( app::WindowBounds(0, 0, m_screenWidth, m_screenHeight) );
	SetWindow(window);
	//m_window->setFullscreen(true);

	Base::onCreate();

	m_gd_driver = ttGDFactory().createDriver();

	if (!m_gd_driver)
		ttThrow( TT_TEXT("Cannot create GD Driver") );

	m_gd_device = m_gd_driver->createDevice( GetWindow() );
	if (!m_gd_device)
		ttThrow( TT_TEXT("Cannot create GD Device") );

	m_gd_context = m_gd_device->deviceContext();

	createTriangles();
}

void SimpleTriangleApp::onUpdate()
{
	update();
	render();

	utils::Sleep(1);
}

void SimpleTriangleApp::onDestroy()
{
	clearTriangles();

	m_gd_context.reset();
	m_gd_device.reset();
	m_gd_driver.reset();

	rm::ResourceManager::DestroyInstance();
	gd::Factory::DestroyInstance();
	app::AppFactory::DestroyInstance();

	Base::onDestroy();
}

//////////////////////////////////////////////////////////////////////////
void SimpleTriangleApp::configRead()
{
	if( !ttDefaultFileSystem().IsExists( io::Path(CONFIG_FILE_NAME) ) )
		return;

	utils::read_xml(CONFIG_FILE_NAME, m_config);

	m_fullScreen = m_config.get("main.fullscreen", m_fullScreen);
	m_screenWidth = m_config.get("main.screenWidth", m_screenWidth);
	m_screenHeight = m_config.get("main.screenHeight", m_screenHeight);
}

void SimpleTriangleApp::configWrite()
{
	m_config.put("main.fullscreen", m_fullScreen);
	m_config.put("main.screenWidth", m_screenWidth);
	m_config.put("main.screenHeight", m_screenHeight);

	utils::write_xml(CONFIG_FILE_NAME, m_config, std::locale(),
		boost::property_tree::xml_writer_make_settings(' ', 4) );
}

void SimpleTriangleApp::createTriangles()
{
	gd::MaterialBuilder materialBuilder(m_gd_device);
	m_material = materialBuilder.createMaterial("shaders/MaterialVSPS.xml");

	SharedPtr<gd::PrimitiveBuilder> primitiveBuilder = m_gd_device->createPrimitiveBuilder();

	SharedPtr<gd::IndexBuffer> indexBuffer = primitiveBuilder->createIndexBuffer(3);

	gd::VertexFormat vertexFormat;
	vertexFormat.addPosition().addColor();
	SharedPtr<gd::VertexBuffer> vertexBuffer = primitiveBuilder->createVertexBuffer(vertexFormat, 3);

	{
		gd::VertexAccessor vertexAccessor(m_gd_context.get(), *vertexBuffer, vertexFormat);
		vertexAccessor.setPosition(0, math::Vector3F(0.0f, 0.5f, 0.5f));
		vertexAccessor.setColor(0, math::Vector3F(1.f, 1.f, 1.f));

		vertexAccessor.setPosition(1, math::Vector3F(0.5f, -0.5f, 0.5f));
		vertexAccessor.setColor(1, math::Vector3F(1.f, 1.f, 1.f));

		vertexAccessor.setPosition(2, math::Vector3F(-0.5f, -0.5f, 0.5f));
		vertexAccessor.setColor(2, math::Vector3F(1.f, 1.f, 1.f));
	}

	m_primitive = primitiveBuilder->createPrimitive();
	m_primitive->setBuffers(indexBuffer, vertexBuffer);
}

void SimpleTriangleApp::clearTriangles()
{
	m_primitive.reset();
	m_material.reset();
}

} //namespace tt
